package monopoly.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.JOptionPane;

import monopoly.Die;
import monopoly.GameState;
import monopoly.Player;
import monopoly.Railroad;
import monopoly.Utility;
import monopoly.StreetProperty;
import monopoly.CardDeck;

public class MonopolyGUI extends JFrame {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static GameState gameState;
	private static GameBoardSpace[] board;
	private static JFrame frame;
	private static BoardGraphics boardGraphics;
	private static JPanel controlPanel, boardPanel, buttonPanel, statusPanel, propertyPanel;
	private static JButton btnRoll, btnPayRent, btnDone, btnPurchase, btnMortgage, btnPayOffMortgage, btnTrade;
	private static JLabel lblName, lblBalance, lblToken, lblGetOutOfJail, lblPosition, lblOwner, lblBlank, lblNotes;
	private static JTable tblPlayerAProperties, tblPlayerBProperties;
	private static JScrollPane scrollPanePlayerOne, scrollPanePlayerTwo;
	private static JTabbedPane tabbedPane;

	
	public MonopolyGUI()
	{
		super("Monopoly");
	}
	
	public void init(Player playerOne, Player playerTwo)
	{
		ButtonHandler handler = new ButtonHandler();
		PropertyTableModel model = new PropertyTableModel(playerOne);
		
		initGameComponents(playerOne, playerTwo);
		initGUI(handler, model);
		

	}
	
	
	private static void initGameComponents(Player playerOne, Player playerTwo)
	{
		GameBoard gameBoard = new GameBoard();
		Die die1 = new Die();
		Die die2 = new Die();
		gameState = new GameState(gameBoard, playerOne, playerTwo, die1, die2, new CardDeck("Chance"), new CardDeck("Community Chest"));
		board = gameState.getGameBoard().getSpaceArray();
	}

	
	
	private static void initGUI(ButtonHandler handler, PropertyTableModel model)
	{
		initFrame();
		initBoardPanel();
		initPropertyPanel(model);
		initButtonPanel(handler);
		initStatusPanel();
		initControlPanel();


		frame.add(boardPanel, BorderLayout.WEST);
		frame.add(controlPanel, BorderLayout.EAST);
		
		frame.pack();
		frame.setVisible(true);		
	}

	
	private static void initFrame()
	{
		frame = new JFrame("Monopoly");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setResizable(false);
		frame.setLayout(new BorderLayout());
		frame.addWindowListener(new WindowAdapter() 
		{
			public void windowClosing(WindowEvent e)
			{
				System.exit(0);
			}
		});		
	}
	
	
	private static void initBoardPanel()
	{
		boardGraphics = new BoardGraphics(gameState);
		
		boardPanel = new JPanel(new BorderLayout());
		boardPanel.add(boardGraphics);
		frame.add(boardPanel, BorderLayout.WEST);

	}
	
	private static void initPropertyPanel(PropertyTableModel model)
	{
		
		Player p1 = gameState.getPlayer1();
		Player p2 = gameState.getPlayer2();
		propertyPanel = new JPanel(new GridLayout(1,1));
		propertyPanel.setBackground(Color.WHITE);
		propertyPanel.setBorder(new EmptyBorder(1,1,1,1));
		
		tabbedPane = new JTabbedPane();

		tblPlayerAProperties = new JTable(model);
		tblPlayerBProperties = new JTable(model);

		scrollPanePlayerOne = new JScrollPane(tblPlayerAProperties);
		scrollPanePlayerTwo = new JScrollPane(tblPlayerBProperties);
		
		tblPlayerAProperties.setPreferredScrollableViewportSize(new Dimension(220, 180));
		tblPlayerBProperties.setPreferredScrollableViewportSize(new Dimension(220, 180));

		tabbedPane.addTab(p1.getName(), scrollPanePlayerOne);
		tabbedPane.addTab(p2.getName(), scrollPanePlayerTwo);

		propertyPanel.add(tabbedPane);
		
		resetTableColumns();

	}
	
	private static void initButtonPanel(ButtonHandler handler)
	{
		buttonPanel = new JPanel(new GridLayout(7,1));
		buttonPanel.setBackground(Color.white);
		buttonPanel.setBorder(new EmptyBorder(1,1,1,1));

		btnRoll = new JButton("Roll Dice");
		btnPayRent = new JButton("Pay Rent");
		btnPurchase = new JButton("Purchase Property");
		btnMortgage = new JButton("Mortgage Property");
		btnPayOffMortgage = new JButton("Pay Off Mortgage");
		btnTrade = new JButton("Trade Properties");
		btnDone = new JButton("Done");


		btnRoll.addActionListener(handler);
		btnPayRent.addActionListener(handler);
		btnPurchase.addActionListener(handler);
		btnMortgage.addActionListener(handler);
		btnPayOffMortgage.addActionListener(handler);
		btnTrade.addActionListener(handler);
		btnDone.addActionListener(handler);

		resetButtons();

		buttonPanel.add(btnRoll);
		buttonPanel.add(btnPayRent);
		buttonPanel.add(btnPurchase);
//		buttonPanel.add(btnMortgage);
//		buttonPanel.add(btnPayOffMortgage);
//		buttonPanel.add(btnTrade);
		buttonPanel.add(btnDone);

	}
	
	private static void initStatusPanel()
	{
		statusPanel = 	new JPanel(new GridLayout(8,1,5,5));
		statusPanel.setBorder(new EmptyBorder(50,30,30,50));
		statusPanel.setBackground(Color.white);
		
		lblName = new JLabel();
		lblToken = new JLabel();
		lblGetOutOfJail = new JLabel();
		lblBalance = new JLabel();
		lblBlank = new JLabel();
		lblPosition = new JLabel();
		lblOwner = new JLabel();
		lblNotes = new JLabel();
		lblNotes.setForeground(Color.red);
		
		updateStatus();

		statusPanel.add(lblName);
		statusPanel.add(lblToken);
		statusPanel.add(lblGetOutOfJail);
		statusPanel.add(lblBalance);
		statusPanel.add(lblBlank);
		statusPanel.add(lblPosition);
		statusPanel.add(lblOwner);
		statusPanel.add(lblNotes);

	}
	private static void initControlPanel()
	{
		controlPanel = 	new JPanel(new BorderLayout());
		controlPanel.setSize(300, 701);
		controlPanel.setBackground(Color.white);
		controlPanel.setBorder(new EmptyBorder(30,30,50,30));
		controlPanel.add(buttonPanel, BorderLayout.SOUTH);
		controlPanel.add(statusPanel, BorderLayout.CENTER);
		controlPanel.add(propertyPanel,BorderLayout.NORTH);
	}

	private static void resetTableColumns()
	{
		tblPlayerAProperties.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		tblPlayerAProperties.getColumnModel().getColumn(0).setPreferredWidth(120);
		tblPlayerAProperties.getColumnModel().getColumn(1).setPreferredWidth(35);
		tblPlayerAProperties.getColumnModel().getColumn(2).setPreferredWidth(65);
		
		tblPlayerBProperties.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		tblPlayerBProperties.getColumnModel().getColumn(0).setPreferredWidth(120);
		tblPlayerBProperties.getColumnModel().getColumn(1).setPreferredWidth(35);
		tblPlayerBProperties.getColumnModel().getColumn(2).setPreferredWidth(65);
	}

	
	private static void resetButtons()
	{
		btnRoll.setEnabled(true);
		btnPayRent.setEnabled(false);
		btnPurchase.setEnabled(false);
		btnMortgage.setEnabled(false);
		btnPayOffMortgage.setEnabled(false);
		btnTrade.setEnabled(false);
		btnDone.setEnabled(false);
	}
	
	private static void updateStatus()
	{
		Player activePlayer = gameState.getActivePlayer();
		Player owner = null;
		String positionName;

		
		positionName = board[activePlayer.getBoardPosition()].getDescription();
		
		Railroad rr = board[activePlayer.getBoardPosition()].getRailroad();
		if (rr != null)
			owner = rr.getOwner();
		else
		{
			Utility util = board[activePlayer.getBoardPosition()].getUtility();
			if (util != null)
				owner = util.getOwner();
			else
			{
				StreetProperty streetProperty = board[activePlayer.getBoardPosition()].getStreetProperty();
				if (streetProperty != null)
					owner = streetProperty.getOwner();
				
			}
			
		}
		
		lblName.setText("Player:     " + activePlayer.getName());
		lblToken.setText("Token:     " + activePlayer.getToken().getTokenName());
		lblGetOutOfJail.setText("Get Out of Jail Free:  " + activePlayer.getGetOutOfJail());
		lblBalance.setText("Cash Balance: " + activePlayer.getBalance());
		lblBlank.setText(" ");
		lblPosition.setText(positionName);
		if (owner != null)
			lblOwner.setText("Owner:     " + owner.getName());
		else
			lblOwner.setText("Owner:");
		lblNotes.setText(" ");
		
		//based on who is active we move the selected index.
		tabbedPane.setSelectedIndex(gameState.getPlayerIndex());
		
	}
	
	
	private class PropertyTableModel extends AbstractTableModel
	{
		private static final long serialVersionUID = 1L;
		private String[] columnNames = {"Property", "Group", "Monopoly"};
		private Object[][] data;

		
		public PropertyTableModel(Player player)
		{
			super();
			data = player.getPropertyData();
		}
		
		public int getColumnCount()
		{
			return columnNames.length;
		}
		
		public int getRowCount()
		{
			return data.length;
		}
		
		public String getColumnName(int col)
		{
			return columnNames[col];
		}
		
		public Object getValueAt(int row, int col)
		{
			return data[row][col];
		}
		
		@SuppressWarnings("unchecked")
		public Class getColumnClass(int c)
		{
			String empty = "Empty";
			try {
				return getValueAt(0, c).getClass();
			} 
			catch (NullPointerException e) 
			{	return  empty.getClass(); }			
		}
	}
	




	private class ButtonHandler implements ActionListener
	{
		public void actionPerformed(ActionEvent event)
		{
			if (event.getActionCommand().equals("Roll Dice"))
			{
				String currentType;
				GameBoardSpace space;
				Player activePlayer = gameState.getActivePlayer();
				
				resetButtons();
				frame.repaint();

				activePlayer.rollAndMove(gameState);
				
				
				/**
				 * Jail handling:
				 */
				if ((activePlayer.isInJail()) || (gameState.getDie1().getFaceValue() != gameState.getDie2().getFaceValue()))
				{
					btnRoll.setEnabled(false);
					btnDone.setEnabled(true);
				}
				updateStatus();
				frame.repaint();
				
				
				/** 
				 * Chance and Community Chest handling:
				 */
				int boardPosition;
				int firstBoardPosition = activePlayer.getBoardPosition();
				
				for (int index=0 ; index < 2 ; index++)
				{
					boardPosition = activePlayer.getBoardPosition();
					space = board[boardPosition];
					if ((index == 0) || (boardPosition != firstBoardPosition))
					{
						if (space.isCard())
							activePlayer.landOnCard(board, gameState);
					}
					updateStatus();
					frame.repaint();
				}

				
				
				/**
				 * Go To Jail Handling
				 */
				boardPosition = activePlayer.getBoardPosition();
				space = board[boardPosition];
				
				currentType = space.getType();
				
				if (currentType.equals("Go To Jail"))
				{
					activePlayer.goToJail();
					activePlayer.move(false,40);
					btnRoll.setEnabled(false);
					btnDone.setEnabled(true);
				}

				

				
				/**
				 * Tax handling
				 */
				if (currentType.equals("Tax"))
				{
					double taxAmount = space.getTax().getTaxAmount(activePlayer);
					activePlayer.adjustBalance(0-taxAmount);
					JOptionPane.showMessageDialog(null, "Tax amount paid:  " + taxAmount);
					updateStatus();
				}
				
				
				/**
				 * Property handling
				 */
				boolean isAvailable = false;
				if (space.isProperty())
					isAvailable = activePlayer.landOnProperty(board, gameState);
				
				if (activePlayer.getRentDue() != 0.0)
				{
					lblNotes.setText("Rent due:   " + activePlayer.getRentDue());
					btnPayRent.setEnabled(true);
					btnRoll.setEnabled(false);
					btnDone.setEnabled(false);
				}
				
				if (isAvailable)
					btnPurchase.setEnabled(true);
				
			}
			
			
			
			
			
			if (event.getActionCommand().equals("Purchase Property"))
			{
				Player activePlayer = gameState.getActivePlayer();
				GameBoardSpace space = board[activePlayer.getBoardPosition()];
				Boolean successful;
				
				successful = activePlayer.purchaseProperty(space);
				

				if (successful) 
				{
					btnPurchase.setEnabled(false);
					if (gameState.getPlayer1() == activePlayer)
					{
						tblPlayerAProperties.setModel(new PropertyTableModel(activePlayer));
						tblPlayerAProperties.repaint();
					}
					else
					{
						tblPlayerBProperties.setModel(new PropertyTableModel(activePlayer));
						tblPlayerBProperties.repaint();
					}
					resetTableColumns();
				} 
				updateStatus();
			}
			
			if (event.getActionCommand().equals("Pay Rent"))
			{
				Player activePlayer = gameState.getActivePlayer();
				int rentMultiplier = activePlayer.getRentMultiplier();
				int diceRollMultiplier = activePlayer.getDiceRollMultiplier();
				
				boolean successful = activePlayer.payRent(gameState, rentMultiplier, diceRollMultiplier);

				if (successful)
				{
					if (gameState.getDie1().getFaceValue() != gameState.getDie2().getFaceValue())
						btnDone.setEnabled(true);
					else
						btnRoll.setEnabled(true);
					
					btnPayRent.setEnabled(false);
					activePlayer.setRentMultiplier(0);
					activePlayer.setDiceRollMultiplier(0);
					activePlayer.setRentDue(0.0);
					
					updateStatus();
				}
			}
			
			if (event.getActionCommand().equals("Done"))
			{
				resetButtons();
				gameState.switchPlayers();
				updateStatus();
				
				frame.repaint();
			}
		}
	}	
}